package com.puzzud.engine.audio;

//import com.puzzud.engine.audio.*;
import com.puzzud.engine.utility.GameShell;

//import java.util.Vector;
import java.io.IOException;
import java.io.File;
import java.io.*;
import java.lang.*;
import javax.sound.sampled.*;
import javax.sound.sampled.LineEvent.Type;
import java.net.*;

import java.util.Vector;
import java.applet.*;

// AudioSample
public class AudioSample
{
	protected AudioInputStream stream;
	protected byte[] samples;
	protected AudioFormat format;
	
	protected ByteArrayInputStream byteStream;
	protected int length;
	
	Vector<Clip> clipList;
	
	protected boolean loop;
	//private int numberOfFrames;
	//protected int currentFrame;
	protected int status;
	
	String fileName;
	
	GameShell gameShell;
	
	public static final int STATUS_PLAYING			= 1;
	public static final int STATUS_LOOPING			= 2;
	public static final int STATUS_STOPPED			= 4;
	public static final int STATUS_PAUSED			= 8;
	public static final int STATUS_FINISHED			= 16;
	
	public AudioSample( GameShell gs )
	{
		int index;
		//Clip tempClip;
		
		// TODO Set a default number of clips as well as the ability to increase?
		clipList = new Vector<Clip>();
		
		/*
		for( index = 0; index < 8; index++ )
		{
			try
			{
				tempClip = javax.sound.sampled.AudioSystem.getClip();
				clipList.add( tempClip );
			}
			catch( LineUnavailableException e ){}
		}
		*/
		
		setLoop( false );
		setStatus( STATUS_STOPPED );
		
		gameShell = gs;
		
		//numberOfFrames = 0;
		//currentFrame = 0;
	}
	
	public void load( String fileName )
	{
		int index;
		//AudioInputStream stream = null;
		
		try
		{
			//sample = javax.sound.sampled.AudioSystem.getAudioInputStream( new File( fileName ) );
			//sample = javax.sound.sampled.AudioSystem.getAudioInputStream( getURL( fileName ) );
			stream = javax.sound.sampled.AudioSystem.getAudioInputStream( getURL( fileName ) );
			
			//byteSample = ( ByteArrayInputStream )tempSample;
		}
		catch( IOException e ){}
		catch( UnsupportedAudioFileException e ){}
		
		format = stream.getFormat();
		
		// Get the number of bytes to read.
		length = ( int )( stream.getFrameLength() * format.getFrameSize() );
		
		// Read the entire stream.
		samples = new byte[length];
		DataInputStream is = new DataInputStream( stream );
		try
		{
			is.readFully( samples );
		}
		catch( IOException ex )
		{
			ex.printStackTrace();
		}
		
		this.fileName = fileName;
		
		//numberOfFrames = clip.getFrameLength();
		//if (clip.isRunning());
		//clip = gameShell.getAudioClip( gameShell.getCodeBase(), fileName );
	}
	
	private URL getURL( String fileName )
	{
		URL url = null;
		
		try
		{
			url = this.getClass().getClassLoader().getResource( fileName );
		}
		catch( Exception e ){}
		
		return( url );
	}
	
	public void play()
	{
		int index;
		Clip tempClip = null;
		
		for( index = 0; index < clipList.size(); index++ )
		{
			tempClip = ( Clip )clipList.elementAt( index );
			
			if( tempClip.isActive() )
			{
				//System.out.println( "!tempClip.isRunning()" );
				//break;
			}
			else
			{
				tempClip = clipList.remove( index-- );
				tempClip.close();
			}
			
			tempClip = null;
		}
		
		//System.out.println( ((Integer)index).toString() );
		
		if( tempClip == null )
		{
			AudioInputStream tempStream;
			
			// Load the audio input stream with information from the samples byte array.
			byteStream = new ByteArrayInputStream( samples );
			tempStream = new AudioInputStream( byteStream, stream.getFormat(), length );
			byteStream = null;
			
			// Load this stream into a clip and add it to the list of active clips.
			try
			{
				tempClip = javax.sound.sampled.AudioSystem.getClip();
				clipList.add( tempClip );
				tempClip.open( tempStream );
			}
			catch( LineUnavailableException e ){}
			catch( IOException e ){}
		}
		
		/*
		if( clip.isRunning() )
		{
			
			synchronized (clip)
			{
                    		clip.notifyAll();  // awaken anyone waiting for this Clip
				clip.stop();
				clip.setFramePosition( 0 );
                	}
			clip.start();
		}
		else
		*/
		
		if( !getLoop() )
		{
			if( tempClip.isActive() )
			{
				//tempClip.stop();
				//tempClip.setFramePosition( tempClip.getBuffersize() - 1 );
				tempClip.setFramePosition( 0 );
			}
			else
			{
				//tempClip.setFramePosition( 0 );
				tempClip.start();
			}
			
			setStatus( STATUS_PLAYING );
		}
		else
		{
			tempClip.loop( Clip.LOOP_CONTINUOUSLY );
			setStatus( STATUS_LOOPING );
		}
		
		/*
		LineListener listener = new LineListener()
		{
			public void update( LineEvent event )
			{
				if( event.getType() != Type.STOP )
				{
					clipList.elementAt( index ).stop();
					clipList.elementAt( index ).setFramePosition( 0 );
					
					System.out.println( "AudioSample ended." );
					
					//setStatus( STATUS_FINISHED );
				}
				else
				if( event.getType() != Type.START )
				{
					//clip.stop();
					//clip.setFramePosition( 0 );
					
					System.out.println( "AudioSample started." );
					
					//setStatus( STATUS_FINISHED );
				}
			}
		};
		
		clipList.elementAt( index ).addLineListener( listener );
		*/
	}
	
	public void pause()
	{
		int index;
		Clip tempClip;
		
		for( index = 0; index < clipList.size(); index++ )
		{
			tempClip = clipList.elementAt( index );
			
			if( tempClip.isActive() )
			{
				tempClip.stop();
			}
		}
		
		setStatus( STATUS_PAUSED );
	}
	
	public void stop()
	{
		int index;
		Clip tempClip;
		
		for( index = 0; index < clipList.size(); index++ )
		{
			tempClip = clipList.elementAt( index );
			
			if( tempClip.isActive() )
			{
				tempClip.stop();
				tempClip.setFramePosition( 0 );
			}
		}
		
		setStatus( STATUS_STOPPED );
	}
	
	public void setLoop( boolean l )
	{
		loop = l;
	}
	
	public boolean getLoop()
	{
		return( loop );
	}
	
	private void setStatus( int s )
	{
		status = s;
	}
	
	public int getStatus()
	{
		if( status == STATUS_LOOPING )
		{
			return( status );
		}
		else
		{
			int index;
			Clip tempClip;
			
			for( index = 0; index < clipList.size(); index++ )
			{
				tempClip = clipList.elementAt( index );
				
				if( tempClip.isActive() )
				{
					status = STATUS_PLAYING;
				}
			}
			
			status = STATUS_FINISHED;
			return( status );
		}
	}
}
